home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-05-22 | 50.8 KB | 2,361 lines |
- Newsgroups: comp.sources.misc
- From: Byron Rakitzis <byron@archone.tamu.edu>
- Subject: v20i011: rc - A Plan 9 shell reimplementation, Part02/04
- Message-ID: <1991May22.154211.3120@sparky.IMD.Sterling.COM>
- Date: Wed, 22 May 1991 15:42:11 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Md4-Signature: 2aa5c82d1e3b0476a2c6d8697913125c
-
- Submitted-by: Byron Rakitzis <byron@archone.tamu.edu>
- Posting-number: Volume 20, Issue 11
- Archive-name: rc/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: fn.c footobar.c glom.c input.c lex.c walk.c
- # Wrapped by kent@sparky on Wed May 22 01:21:49 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 2 (of 4)."'
- if test -f 'fn.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'fn.c'\"
- else
- echo shar: Extracting \"'fn.c'\" \(4435 characters\)
- sed "s/^X//" >'fn.c' <<'END_OF_FILE'
- X/*
- X fn.c: functions for adding and deleting functions from the symbol table.
- X Support for signal handlers is also found here.
- X*/
- X
- X#include <signal.h>
- X#include "rc.h"
- X#include "utils.h"
- X#include "status.h"
- X#include "tree.h"
- X#include "hash.h"
- X#include "footobar.h"
- X#include "walk.h"
- X#include "nalloc.h"
- X#include "sigmsgs.h"
- X#include "builtins.h"
- X#include "input.h"
- X
- Xstatic void fn_handler(int);
- X
- Xstatic Node *handlers[NUMOFSIGNALS], null_function;
- Xstatic boolean runexit = FALSE;
- X
- X/* set signals to default values for rc. this means that interactive shells ignore SIGQUIT, etc. */
- X
- Xvoid inithandler() {
- X if (interactive) {
- X signal(SIGINT, sig);
- X handlers[SIGINT] = &null_function;
- X if (!dashdee) {
- X signal(SIGQUIT, SIG_IGN);
- X handlers[SIGQUIT] = &null_function;
- X }
- X }
- X null_function.type = BODY;
- X null_function.u[0].p = null_function.u[1].p = NULL;
- X}
- X
- X/* only run this in a child process! resets signals to their default values */
- X
- Xvoid setsigdefaults(void) {
- X int i;
- X
- X /*
- X General housekeeping: (setsigdefaults happens after fork(), so it's a convenient
- X place to clean up)
- X */
- X
- X interactive = FALSE;
- X if (histstr != NULL) /* Close an open history file */
- X close(histfd);
- X
- X /* Restore signals to SIG_DFL */
- X
- X for (i = 1; i < NUMOFSIGNALS; i++) { /* signal 0 is never used (bogus) */
- X if (handlers[i] != NULL) {
- X handlers[i] = NULL;
- X signal(i, SIG_DFL);
- X }
- X }
- X runexit = FALSE; /* No sigexit on subshells */
- X}
- X
- X/* rc's exit. if runexit is set, run the sigexit function. */
- X
- Xvoid rc_exit(int stat) {
- X static char *sigexit[2] = { "sigexit", NULL };
- X
- X if (runexit) {
- X runexit = FALSE;
- X funcall(sigexit);
- X exit(getstatus());
- X } else {
- X exit(stat);
- X }
- X}
- X
- X/* the signal handler for all functions. calls walk() */
- X
- Xstatic void fn_handler(int s) {
- X if (s < 0 || s >= NUMOFSIGNALS)
- X rc_error("unknown signal!?");
- X
- X signal(s, fn_handler); /* sgi seems to require re-signalling */
- X walk(handlers[s], TRUE);
- X}
- X
- X/*
- X assign a function in Node form. Check to see if the function is also a signal, and set the
- X signal vectors appropriately.
- X*/
- X
- Xvoid fnassign(char *name, Node *def) {
- X Node *newdef = treecpy(def == NULL ? &null_function : def, ealloc); /* important to do the treecopy first */
- X Function *new = get_fn_place(name);
- X int i;
- X
- X new->def = newdef;
- X new->extdef = NULL;
- X
- X if (strncmp(name, "sig", sizeof "sig" - 3) == 0) { /* slight optimization */
- X if (streq(name, "sigexit"))
- X runexit = TRUE;
- X for (i = 1; i < NUMOFSIGNALS; i++) /* zero is a bogus signal */
- X if (streq(signals[i][0], name)) {
- X if (newdef != NULL) {
- X handlers[i] = newdef;
- X signal(i, fn_handler);
- X } else {
- X handlers[i] = &null_function;
- X signal(i, SIG_IGN);
- X }
- X break;
- X }
- X }
- X}
- X
- X/* assign a function from the environment. store just the external representation */
- X
- Xvoid fnassign_string(char *extdef) {
- X char *name = get_name(extdef+3); /* +3 to skip over "fn_" */
- X Function *new;
- X
- X if (name == NULL)
- X return;
- X
- X new = get_fn_place(name);
- X new->def = NULL;
- X new->extdef = ecpy(extdef);
- X}
- X
- X/* return a function in Node form, evaluating an entry from the environment if necessary */
- X
- XNode *fnlookup(char *name) {
- X Function *look = lookup_fn(name);
- X Node *ret;
- X
- X if (look == NULL)
- X return NULL; /* not found */
- X if (look->def != NULL)
- X return look->def;
- X if (look->extdef == NULL) /* function was set to null, e.g., fn foo {} */
- X return &null_function;
- X
- X ret = parse_fn(name, look->extdef);
- X
- X if (ret == NULL) {
- X efree(look->extdef);
- X look->extdef = NULL;
- X return &null_function;
- X } else {
- X return look->def = treecpy(ret, ealloc); /* Need to take it out of talloc space */
- X }
- X}
- X
- X/* return a function in string form (used by makeenv) */
- X
- Xchar *fnlookup_string(char *name) {
- X Function *look = lookup_fn(name);
- X
- X if (look == NULL)
- X return NULL;
- X if (look->extdef != NULL)
- X return look->extdef;
- X return look->extdef = fun2str(name, look->def);
- X}
- X
- X/*
- X remove a function from the symbol table. If it also defines a signal handler, restore the signal handler
- X to its default value.
- X*/
- X
- Xvoid fnrm(char *name) {
- X int i;
- X
- X for (i = 1; i < NUMOFSIGNALS; i++) /* signal 0 unused */
- X if (streq(signals[i][0], name)) {
- X handlers[i] = NULL;
- X if (i == SIGINT)
- X signal(i, sig); /* restore default signal handler for rc */
- X else if (i == SIGQUIT && !dashdee)
- X signal(i, SIG_IGN); /* ditto */
- X else
- X signal(i, SIG_DFL);
- X }
- X
- X if (streq(name, "sigexit"))
- X runexit = FALSE;
- X
- X delete_fn(name);
- X}
- END_OF_FILE
- if test 4435 -ne `wc -c <'fn.c'`; then
- echo shar: \"'fn.c'\" unpacked with wrong size!
- fi
- # end of 'fn.c'
- fi
- if test -f 'footobar.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'footobar.c'\"
- else
- echo shar: Extracting \"'footobar.c'\" \(7836 characters\)
- sed "s/^X//" >'footobar.c' <<'END_OF_FILE'
- X/*
- X footobar.c: a collection of functions to convert internal representations of
- X variables and functions to external representations, and vice versa
- X*/
- X
- X#include "rc.h"
- X#include "utils.h"
- X#include "lex.h"
- X#include "footobar.h"
- X#include "nalloc.h"
- X#include "input.h"
- X#include "list.h"
- X
- X#define FSCHAR '\1'
- X#define FSSTRING "\1"
- X
- Xstatic char *getenvw(char *, boolean);
- Xstatic void funcat(char *);
- Xstatic void strtree(Node *);
- X
- Xstatic char *fun;
- Xstatic SIZE_T funsize, funpos;
- X
- X/* a specialized strcat, used in strtree */
- X
- Xstatic void funcat(char *s) {
- X SIZE_T l = strlen(s);
- X char *new;
- X
- X if (l + funpos > funsize) {
- X new = nalloc(funsize *= 2);
- X memcpy(new, fun, funpos);
- X new[funpos] = 0;
- X fun = new;
- X }
- X strcpy(fun + funpos, s);
- X funpos += l;
- X}
- X
- X/* used to turn a function in Node * form into something we can export to the environment */
- X
- Xchar *fun2str(char *name, Node *s) {
- X fun = nalloc(funsize = 512);
- X funpos = 0;
- X funcat("fn_");
- X funcat(name);
- X funcat("={");
- X strtree(s);
- X funcat("}");
- X return ecpy(fun); /* put into malloc space */
- X}
- X
- X/* ptree is used by whatis in order to print the definition of a function to the terminal */
- X
- Xchar *ptree(Node *s) {
- X fun = nalloc(funsize = 512);
- X funpos = 0;
- X fun[0] = 0;
- X strtree(s);
- X return fun;
- X}
- X
- X/* save some code space by gathering this operation in a function */
- X
- Xstatic void catredir(int i) {
- X switch (i) {
- X case CREATE: funcat(">"); break;
- X case APPEND: funcat(">>"); break;
- X case HEREDOC: funcat("<<"); break;
- X case HERESTRING: funcat("<<<"); break;
- X case FROM: funcat("<"); break;
- X }
- X}
- X
- X/* convert a function in Node * form into something rc can parse (and humans can read?) */
- X
- Xstatic void strtree(Node *n) {
- X int defaultfd;
- X char b[16];
- X
- X if (n == NULL) {
- X funcat("()");
- X return;
- X }
- X
- X switch (n->type) {
- X case rDUP:
- X catredir(n->u[0].i);
- X if (n->u[2].i != -1)
- X sprint(b, "[%d=%d]", n->u[1].i, n->u[2].i);
- X else
- X sprint(b, "[%d=]", n->u[1].i);
- X funcat(b);
- X break;
- X case rWORD:
- X if (*n->u[0].s == '\'')
- X funcat(strprint(n->u[0].s + 1, TRUE, FALSE));
- X else
- X funcat(strprint(n->u[0].s, FALSE, FALSE));
- X break;
- X case BACKQ:
- X if (n->u[0].p != NULL && n->u[0].p->type == VAR
- X && n->u[0].p->u[0].p != NULL && n->u[0].p->u[0].p->type == rWORD
- X && streq(n->u[0].p->u[0].p->u[0].s,"ifs")) {
- X funcat("`{");
- X } else {
- X funcat("``");
- X strtree(n->u[0].p);
- X funcat("{");
- X }
- X strtree(n->u[1].p);
- X funcat("}");
- X break;
- X case rBANG:
- X funcat("! ");
- X strtree(n->u[0].p);
- X break;
- X case NOWAIT:
- X strtree(n->u[0].p);
- X funcat("&");
- X break;
- X case rCOUNT:
- X funcat("$#");
- X strtree(n->u[0].p);
- X break;
- X case rFLAT:
- X funcat("$^");
- X strtree(n->u[0].p);
- X break;
- X case RMFN:
- X funcat("fn ");
- X strtree(n->u[0].p);
- X break;
- X case rSUBSHELL:
- X funcat("@ ");
- X strtree(n->u[0].p);
- X break;
- X case VAR:
- X funcat("$");
- X strtree(n->u[0].p);
- X break;
- X case rANDAND:
- X strtree(n->u[0].p);
- X funcat("&&");
- X strtree(n->u[1].p);
- X break;
- X case ASSIGN:
- X strtree(n->u[0].p);
- X funcat("=");
- X strtree(n->u[1].p);
- X break;
- X case BODY:
- X if (n->u[1].p != NULL)
- X funcat("{");
- X strtree(n->u[0].p);
- X if (n->u[1].p != NULL) {
- X funcat(";");
- X strtree(n->u[1].p);
- X funcat("}");
- X }
- X break;
- X case BRACE:
- X funcat("{");
- X strtree(n->u[0].p);
- X funcat("}");
- X strtree(n->u[1].p);
- X break;
- X case CONCAT:
- X strtree(n->u[0].p);
- X funcat("^");
- X strtree(n->u[1].p);
- X break;
- X case rELSE:
- X funcat("{");
- X strtree(n->u[0].p);
- X funcat("}else ");
- X strtree(n->u[1].p);
- X break;
- X case EPILOG:
- X case PRE:
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X break;
- X case NEWFN:
- X funcat("fn ");
- X strtree(n->u[0].p);
- X funcat(" {");
- X strtree(n->u[1].p);
- X funcat("}");
- X break;
- X case rIF:
- X funcat("if(");
- X strtree(n->u[0].p);
- X funcat(")");
- X strtree(n->u[1].p);
- X break;
- X case rOROR:
- X strtree(n->u[0].p);
- X funcat("||");
- X strtree(n->u[1].p);
- X break;
- X case ARGS:
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X break;
- X case rSWITCH:
- X funcat("switch(");
- X strtree(n->u[0].p);
- X funcat(")");
- X strtree(n->u[1].p);
- X break;
- X case MATCH:
- X funcat("~ ");
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X break;
- X case VARSUB:
- X funcat("$");
- X strtree(n->u[0].p);
- X funcat("(");
- X strtree(n->u[1].p);
- X funcat(")");
- X break;
- X case rWHILE:
- X funcat("while(");
- X strtree(n->u[0].p);
- X funcat(")");
- X strtree(n->u[1].p);
- X break;
- X case LAPPEND:
- X funcat("(");
- X strtree(n->u[0].p);
- X funcat(" ");
- X strtree(n->u[1].p);
- X funcat(")");
- X break;
- X case FORIN:
- X funcat("for(");
- X strtree(n->u[0].p);
- X funcat(" in ");
- X strtree(n->u[1].p);
- X funcat(")");
- X strtree(n->u[2].p);
- X break;
- X case rPIPE:
- X funcat("{");
- X strtree(n->u[2].p);
- X if (n->u[0].i == 1) {
- X if (n->u[1].i == 0)
- X sprint(b, "}|{");
- X else
- X sprint(b, "}|[1=%d]{", n->u[1].p);
- X } else {
- X if (n->u[1].i == 0)
- X sprint(b, "}|[%d]{", n->u[0].p);
- X else
- X sprint(b, "}|[%d=%d]{", n->u[0].i, n->u[1].i);
- X }
- X funcat(b);
- X strtree(n->u[3].p);
- X funcat("}");
- X break;
- X case NMPIPE:
- X catredir(n->u[0].i);
- X if (n->u[1].i != 1) {
- X sprint(b, "[%d]{", n->u[1].i);
- X funcat(b);
- X } else
- X funcat("{");
- X strtree(n->u[2].p);
- X funcat("}");
- X break;
- X case rREDIR:
- X defaultfd = (n->u[0].i == CREATE || n->u[0].i == APPEND);
- X catredir(n->u[0].i);
- X if (n->u[1].i != defaultfd) {
- X sprint(b, "[%d]", n->u[1].i);
- X funcat(b);
- X }
- X strtree(n->u[2].p);
- X break;
- X }
- X}
- X
- X/* convert a List to a string, separating it with ^A characters. Used for exporting variables to the environment */
- X
- Xchar *list2str(char *name, List *s) {
- X SIZE_T size;
- X List *t;
- X char *w;
- X
- X size = listlen(s);
- X size += strlen(name);
- X
- X w = ealloc(size + 2);
- X t = s;
- X strcpy(w, name);
- X strcat(w, "=");
- X strcat(w, t->w);
- X for (s = s->n; s != NULL; s = s->n) {
- X strcat(w, FSSTRING);
- X strcat(w, s->w);
- X }
- X return w;
- X}
- X
- X/* convert a List to an array, for execve() */
- X
- Xchar **list2array(List *s, boolean print) {
- X char **av;
- X int i;
- X
- X av = nalloc((listnel(s) + 1) * sizeof (char *));
- X
- X for (i = 0; s != NULL; i++) {
- X av[i] = s->w;
- X if (print)
- X fprint(2,"%s",s->w);
- X s = s->n;
- X if (print) {
- X if (s == NULL)
- X fprint(2,"\n");
- X else
- X fprint(2," ");
- X }
- X }
- X av[i] = NULL;
- X return av;
- X}
- X
- X/* figure out the name of a variable given an environment string. copy this into malloc space */
- X
- Xchar *get_name(char *s) {
- X char *r;
- X SIZE_T i;
- X
- X for (i = 0; s[i] != '\0' && s[i] != '='; i++)
- X ;
- X
- X if (s[i] == '\0')
- X return NULL;
- X
- X r = ealloc(i + 1);
- X
- X r[i] = '\0';
- X
- X while (i > 0) {
- X --i;
- X r[i] = s[i];
- X }
- X return r;
- X}
- X
- X/* get the next word from a variable's value as represented in the environment. */
- X
- Xstatic char *getenvw(char *s, boolean saw_alpha) {
- X char *r;
- X SIZE_T i,j;
- X
- X for (i = j = 0; s[i] != '\0' && s[i] != FSCHAR; i++)
- X ;
- X
- X if (i == 0)
- X if(s[i] == '\0' && !saw_alpha)
- X return NULL;
- X else {
- X r = enew(char);
- X *r = '\0';
- X return r;
- X }
- X
- X r = ealloc(i + j + 1);
- X
- X r[i + j] = '\0';
- X
- X while (i > 0) {
- X --i;
- X r[i + j] = s[i];
- X }
- X return r;
- X}
- X
- X/* take an environment entry for a variable (elements ^A separated) and turn it into a List */
- X
- XList *parse_var(char *name, char *extdef) {
- X List *r, *top = r;
- X char *f;
- X boolean saw_alpha;
- X
- X top = r = enew(List);
- X extdef += strlen(name) + 1;
- X
- X
- X if ((f = getenvw(extdef, FALSE)) == NULL)
- X return NULL;
- X
- X while (1) {
- X r->w = f;
- X r->m = NULL;
- X extdef += strlen(f);
- X if (*extdef == FSCHAR) {
- X extdef++;
- X saw_alpha = TRUE;
- X } else {
- X saw_alpha = FALSE;
- X }
- X if ((f = getenvw(extdef, saw_alpha)) == NULL) {
- X r->n = NULL;
- X break;
- X }
- X r = r->n = enew(List);
- X }
- X return top;
- X}
- X
- X/* get an environment entry for a function and have rc parse it. */
- X
- XNode *parse_fn(char *name, char *extdef) {
- X Node *def;
- X int len;
- X
- X len = strlen(name);
- X extdef[2] = ' ';
- X extdef[3 + len] = ' ';
- X def = parseline(extdef);
- X extdef[2] = '_';
- X extdef[3 + len] = '=';
- X
- X if (def == NULL || def->type != NEWFN)
- X return NULL;
- X else
- X return def->u[1].p;
- X}
- END_OF_FILE
- if test 7836 -ne `wc -c <'footobar.c'`; then
- echo shar: \"'footobar.c'\" unpacked with wrong size!
- fi
- # end of 'footobar.c'
- fi
- if test -f 'glom.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'glom.c'\"
- else
- echo shar: Extracting \"'glom.c'\" \(8367 characters\)
- sed "s/^X//" >'glom.c' <<'END_OF_FILE'
- X/* glom.c: builds an argument list out of words, variables, etc. */
- X
- X#ifndef NONMPIPES
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#endif
- X#include "rc.h"
- X#include "utils.h"
- X#include "nalloc.h"
- X#include "glom.h"
- X#include "hash.h"
- X#include "walk.h"
- X#include "status.h"
- X#include "exec.h"
- X#include "lex.h"
- X#include "open.h"
- X#include "list.h"
- X
- Xstatic List *backq(Node *, Node *);
- Xstatic List *bqinput(List *, int);
- Xstatic List *count(List *);
- Xstatic List *mknmpipe(Node *);
- X
- XRq *redirq = NULL;
- XList *fifoq = NULL;
- X
- XList *word(char *w, char *m) {
- X List *s;
- X
- X if (w == NULL)
- X return NULL;
- X if (*w == '\'') {
- X m = NULL; /* m is null, or had better be! */
- X w++;
- X }
- X
- X s = nnew(List);
- X s->w = w;
- X s->m = m;
- X s->n = NULL;
- X return s;
- X}
- X
- X/*
- X Append list s2 to list s1 by copying s1 and making the new copy
- X point at s2.
- X*/
- X
- XList *append(List *s1, List *s2) {
- X List *r, *top;
- X
- X if (s1 == NULL)
- X return s2;
- X if (s2 == NULL)
- X return s1;
- X
- X r = top = nnew(List);
- X while (1) {
- X r->w = s1->w;
- X r->m = s1->m;
- X if ((s1 = s1->n) == NULL)
- X break;
- X r = r->n = nnew(List);
- X }
- X
- X r->n = s2;
- X
- X return top;
- X}
- X
- XList *concat(List *s1, List *s2) {
- X int n1, n2;
- X SIZE_T y,z;
- X List *n, *s;
- X
- X if (s1 == NULL)
- X return s2;
- X if (s2 == NULL)
- X return s1;
- X
- X n1 = listnel(s1);
- X n2 = listnel(s2);
- X
- X if (n1 != n2 && n1 != 1 && n2 != 1)
- X rc_error("bad concatenation");
- X
- X n = s = nnew(List);
- X
- X while (1) {
- X z = strlen(s1->w) + strlen(s2->w) + 1;
- X n->w = nalloc(z);
- X strcpy(n->w,s1->w);
- X strcat(n->w,s2->w);
- X if (s1->m == NULL && s2->m == NULL) {
- X n->m = NULL;
- X } else {
- X n->m = nalloc(z);
- X y = strlen(s1->w);
- X if (s1->m == NULL)
- X clear(n->m, y);
- X else
- X memcpy(n->m, s1->m, y);
- X if (s2->m == NULL)
- X clear(n->m + y, strlen(s2->w));
- X else
- X memcpy(n->m + y, s2->m, strlen(s2->w));
- X n->m[z] = 0;
- X }
- X if (n1 > 1)
- X s1 = s1->n;
- X if (n2 > 1)
- X s2 = s2->n;
- X if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1)) {
- X n->n = NULL;
- X return s;
- X }
- X n->n = nnew(List);
- X n = n->n;
- X }
- X}
- X
- XList *varsub(List *v, List *subs) {
- X int i,j;
- X int n;
- X List *r,*s;
- X List *top,*cat;
- X
- X n = listnel(v);
- X
- X top = cat = NULL;
- X
- X for (s = subs; s != NULL; s = s->n) {
- X i = a2u(s->w);
- X if (i < 1)
- X rc_error("bad subscript");
- X if (i <= n) {
- X for (j = 1, r = v; j != i; j++, r = r->n)
- X ; /* loop until r == v(i) */
- X if (top == NULL) {
- X top = cat = nnew(List);
- X } else {
- X cat->n = nnew(List);
- X cat = cat->n;
- X }
- X cat->w = r->w;
- X cat->m = r->m;
- X }
- X }
- X
- X if (top == NULL)
- X return NULL;
- X
- X cat->n = NULL;
- X return top;
- X}
- X
- XList *flatten(List *s) {
- X List *r;
- X
- X if (s == NULL || s->n == NULL)
- X return s;
- X
- X r = nnew(List);
- X r->w = nalloc(listlen(s) + 1);
- X r->m = NULL; /* flattened lists come from variables, so no meta */
- X r->n = NULL;
- X
- X strcpy(r->w, s->w);
- X
- X do {
- X s = s->n;
- X strcat(r->w, " ");
- X strcat(r->w, s->w);
- X } while (s->n != NULL);
- X
- X return r;
- X}
- X
- Xstatic List *count(List *l) {
- X List *s = nnew(List);
- X char buf[16];
- X
- X s->w = ncpy(sprint(buf, "%d", listnel(l)));
- X s->n = NULL;
- X s->m = NULL;
- X return s;
- X}
- X
- Xvoid assign(List *s1, List *s2, boolean stack) {
- X List *val = s2;
- X
- X if (s1 == NULL)
- X rc_error("null variable name");
- X if (s1->n != NULL)
- X rc_error("multi-word variable name");
- X if (*s1->w == '\0')
- X rc_error("zero-length variable name");
- X if (a2u(s1->w) != -1)
- X rc_error("numeric variable name");
- X if (s1->w[0] == '*' && s1->w[1] == '\0')
- X val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
- X
- X if (s2 != NULL || stack) {
- X varassign(s1->w, val, stack);
- X alias(s1->w, val, stack);
- X } else
- X varrm(s1->w, stack);
- X}
- X
- X/*
- X The following two functions are by the courtesy of Paul Haahr,
- X who could not stand the incompetence of my own backquote implementation.
- X*/
- X
- X#define BUFSIZE ((SIZE_T) 1000)
- X
- Xstatic List *bqinput(List *list, int fd) {
- X char *s, *bufend;
- X List *lp, *prev;
- X SIZE_T nremain, bufsize;
- X static char isifs[256];
- X
- X clear(isifs, sizeof isifs);
- X isifs['\0'] = 1;
- X for (lp = list; list != NULL; list = list->n)
- X for (s = list->w; *s != '\0'; s++)
- X isifs[*(unsigned char *)s] = 1;
- X
- X nremain = bufsize = BUFSIZE;
- X lp = list = nnew(List);
- X s = list->w = nalloc(bufsize + 1);
- X list->m = NULL;
- X prev = NULL;
- X while (1) {
- X int n;
- X
- X if (nremain == 0) {
- X SIZE_T m = s - lp->w;
- X char *buf;
- X
- X while (bufsize < m + BUFSIZE)
- X bufsize *= 2;
- X buf = nalloc(bufsize + 1);
- X memcpy(buf, lp->w, m);
- X lp->w = buf;
- X lp->m = NULL;
- X s = &buf[m];
- X nremain = bufsize - m;
- X }
- X n = read(fd, s, nremain);
- X if (n <= 0) {
- X if (n == -1) {
- X uerror("backquote read");
- X rc_error(NULL);
- X }
- X /* break */ break;
- X }
- X nremain -= n;
- X for (bufend = &s[n]; s < bufend; s++)
- X if (isifs[*(unsigned char *)s]) {
- X *s = '\0';
- X prev = lp;
- X lp = nnew(List);
- X lp->w = s + 1;
- X lp->m = NULL;
- X prev->n = lp;
- X }
- X }
- X
- X if (s == lp->w) {
- X if (prev == NULL)
- X list = NULL;
- X else
- X prev->n = NULL;
- X } else {
- X lp->n = NULL;
- X *s = '\0';
- X }
- X
- X return list;
- X}
- X
- Xstatic List *backq(Node *ifsnode, Node *n) {
- X int p[2], pid, sp;
- X List *result, *ifs;
- X
- X if (n == NULL)
- X return NULL;
- X
- X if (pipe(p) < 0) {
- X uerror("pipe");
- X rc_error(NULL);
- X }
- X
- X switch (pid = fork()) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X setsigdefaults();
- X dup2(p[1],1);
- X close(p[0]);
- X close(p[1]);
- X redirq = NULL;
- X fifoq = NULL;
- X walk(n, FALSE);
- X exit(getstatus());
- X /* NOTREACHED */
- X default:
- X ifs = glom(ifsnode);
- X close(p[1]);
- X result = bqinput(ifs, p[0]);
- X close(p[0]);
- X while (pid != wait(&sp))
- X ;
- X statprint(sp);
- X return result;
- X }
- X}
- X
- Xvoid qredir(Node *n) {
- X Rq *next;
- X
- X if (redirq == NULL) {
- X next = redirq = nnew(Rq);
- X } else {
- X for (next = redirq; next->n != NULL; next = next->n)
- X ;
- X next->n = nnew(Rq);
- X next = next->n;
- X }
- X
- X next->r = n;
- X next->n = NULL;
- X}
- X
- Xstatic List *mknmpipe(Node *n) {
- X#ifdef NONMPIPES
- X rc_error("named pipes are not supported");
- X return NULL;
- X#else
- X int fd;
- X char *fifoname, buf[32];
- X List *fifolist = nnew(List);
- X List *f = nnew(List);
- X static int fifonumber = 0;
- X
- X fifoname = ncpy(sprint(buf,"/tmp/rc%d.%d", getpid(), fifonumber++));
- X
- X if (mknod(fifoname, S_IFIFO | 0644, 0) < 0) {
- X uerror("mknod");
- X return NULL;
- X }
- X
- X switch (fork()) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X setsigdefaults();
- X fd = rc_open(fifoname, CREATE);
- X if (fd < 0) {
- X uerror("open");
- X exit(1);
- X }
- X if (dup2(fd, (n->u[0].i == FROM)) < 0) { /* stupid hack */
- X uerror("dup2");
- X exit(1);
- X }
- X close(fd);
- X redirq = NULL;
- X fifoq = NULL;
- X walk(n->u[2].p, FALSE);
- X exit(getstatus());
- X /* NOTREACHED */
- X default:
- X f->w = fifoname;
- X f->n = fifoq;
- X fifoq = f;
- X
- X fifolist->w = fifoname;
- X fifolist->m = NULL;
- X fifolist->n = NULL;
- X
- X return fifolist;
- X }
- X#endif
- X}
- X
- XList *glom(Node *n) {
- X Node *words;
- X List *v, *first, *last;
- X boolean dollarstar;
- X
- X if (n == NULL)
- X return NULL;
- X
- X switch (n->type) {
- X case ARGS:
- X case LAPPEND:
- X words = n->u[0].p;
- X last = NULL;
- X while (words != NULL && (words->type == ARGS || words->type == LAPPEND)) {
- X if (words->u[1].p != NULL && words->u[1].p->type != rWORD)
- X break;
- X first = glom(words->u[1].p);
- X if (first != NULL) {
- X first->n = last;
- X last = first;
- X }
- X words = words->u[0].p;
- X }
- X return append(append(glom(words), last), glom(n->u[1].p));
- X case BACKQ:
- X return backq(n->u[0].p,n->u[1].p);
- X case CONCAT:
- X first = glom(n->u[0].p); /* force left-to-right evaluation */
- X return concat(first, glom(n->u[1].p));
- X case rDUP:
- X case rREDIR:
- X qredir(n);
- X return NULL;
- X case rWORD:
- X return word(n->u[0].s,n->u[1].s);
- X case NMPIPE:
- X return mknmpipe(n);
- X default:
- X break;
- X }
- X
- X /*
- X the next three operations depend on the left-child of glom
- X to be a variable name. Therefore they are all treated here.
- X (previously each function looked up and checked the validity
- X of a variable name)
- X */
- X
- X v = glom(n->u[0].p);
- X if (v == NULL)
- X rc_error("null variable name");
- X if (v->n != NULL)
- X rc_error("multi-word variable name");
- X if (*v->w == '\0')
- X rc_error("zero-length variable name");
- X
- X dollarstar = (v->w[0] == '*' && v->w[1] == '\0');
- X v = varlookup(v->w);
- X if (dollarstar)
- X v = v->n;
- X
- X switch (n->type) {
- X default:
- X fprint(2,"glom: this can't happen\n");
- X exit(1);
- X /* NOTREACHED */
- X case rCOUNT:
- X return count(v);
- X case rFLAT:
- X return flatten(v);
- X case VAR:
- X return v;
- X case VARSUB:
- X return varsub(v, glom(n->u[1].p));
- X }
- X
- X}
- END_OF_FILE
- if test 8367 -ne `wc -c <'glom.c'`; then
- echo shar: \"'glom.c'\" unpacked with wrong size!
- fi
- # end of 'glom.c'
- fi
- if test -f 'input.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'input.c'\"
- else
- echo shar: Extracting \"'input.c'\" \(6937 characters\)
- sed "s/^X//" >'input.c' <<'END_OF_FILE'
- X/* input.c: i/o routines for files and pseudo-files (strings) */
- X
- X#include <errno.h>
- X#include <setjmp.h>
- X#include <stdarg.h>
- X#include "rc.h"
- X#include "input.h"
- X#include "utils.h"
- X#include "walk.h"
- X#include "hash.h"
- X#include "lex.h"
- X#include "open.h"
- X#include "nalloc.h"
- X#include "except.h"
- X#include "glom.h"
- X#include "builtins.h"
- X#include "parse.h"
- X#include "tree.h"
- X
- X/*
- X warning, changes have been made to (fd|string)(gchar|ugchar) so that
- X you cannot unget EOF more than once. lex.c never does this, so I'm
- X safe, but if you unget EOF more than once, expect to be able to read
- X it back only once. The reason is that EOF is an int, whereas the buffers
- X are character buffers.
- X*/
- X
- Xtypedef struct Input {
- X enum inputtype t;
- X char *ibuf;
- X int fd;
- X int index;
- X int read;
- X int lineno;
- X} Input;
- X
- X#define BUFSIZE ((SIZE_T) 256)
- X
- X#ifdef READLINE
- Xextern char *readline(char *);
- Xextern void add_history(char *);
- Xstatic char *rlinebuf;
- X#endif
- X
- Xchar *prompt, *prompt2;
- Xboolean rcrc;
- Xchar *histstr;
- Xint histfd;
- X
- Xstatic int dead(void);
- Xstatic int fdgchar(void);
- Xstatic int stringgchar(void);
- Xstatic void history(void);
- Xstatic void ugdead(int);
- X
- Xstatic char *inbuf;
- Xstatic SIZE_T istacksize, chars_out, chars_in;
- Xstatic boolean eofread = FALSE;
- Xstatic Input *istack, *itop;
- X
- Xstatic int (*realgchar)(void);
- Xstatic void (*realugchar)(int);
- X
- Xint last;
- X
- Xint gchar(void) {
- X if (eofread) {
- X eofread = FALSE;
- X return last = EOF;
- X }
- X return realgchar();
- X}
- X
- Xvoid ugchar(int c) {
- X realugchar(c);
- X}
- X
- Xstatic int dead() {
- X return last = EOF;
- X}
- X
- Xstatic void ugdead(int c) {
- X return;
- X}
- X
- Xstatic void ugalive(int c) {
- X if (c == EOF)
- X eofread = TRUE;
- X else
- X inbuf[--chars_out] = c;
- X}
- X
- X/* get the next character from a string. */
- X
- Xstatic int stringgchar() {
- X return last = (inbuf[chars_out] == '\0' ? EOF : inbuf[chars_out++]);
- X}
- X
- X/*
- X read a character from a file-descriptor. If GNU readline is defined, add a newline and doctor
- X the buffer to look like a regular fdgchar buffer.
- X*/
- X
- Xstatic int fdgchar() {
- X if (chars_out >= chars_in + 2) { /* has the buffer been exhausted? if so, replenish it */
- X do {
- X#ifdef READLINE
- X if (interactive && istack->fd == 0) {
- X rlinebuf = readline(prompt);
- X if (rlinebuf == NULL) {
- X chars_in = 0;
- X } else {
- X if (*rlinebuf != '\0')
- X add_history(rlinebuf);
- X chars_in = strlen(rlinebuf) + 1;
- X efree(inbuf);
- X inbuf = ealloc(chars_in + 3);
- X strcpy(inbuf+2, rlinebuf);
- X strcat(inbuf+2, "\n");
- X efree(rlinebuf);
- X }
- X } else
- X#endif
- X chars_in = read(istack->fd, inbuf + 2, BUFSIZE);
- X } while (chars_in == -1 && errno == EINTR); /* Suppose it was interrupted by a signal */
- X
- X switch (chars_in) {
- X case 0:
- X return last = EOF;
- X case -1:
- X uerror("read");
- X rc_exit(1);
- X /* NOTREACHED */
- X default:
- X chars_out = 2;
- X if (dashvee)
- X writeall(2, inbuf + 2, chars_in);
- X history();
- X }
- X }
- X return last = inbuf[chars_out++];
- X}
- X
- X/* set up the input stack, and put a "dead" input at the bottom, so that yyparse will always read eof */
- X
- Xvoid initinput() {
- X istack = itop = ealloc(istacksize = 256 * sizeof (Input));
- X istack->t = FD;
- X istack->fd = -1;
- X realugchar = ugalive;
- X}
- X
- X/* push an input source onto the stack. set up a new input buffer, and set the right getchar() */
- X
- Xvoid pushinput(int /*enum inputtype*/ t,...) {
- X SIZE_T count, idiff;
- X char **a;
- X va_list ap;
- X
- X va_start(ap, t);
- X
- X istack->index = chars_out;
- X istack->read = chars_in;
- X istack->ibuf = inbuf;
- X istack->lineno = lineno;
- X istack++;
- X
- X idiff = istack - itop;
- X
- X if (idiff >= istacksize / sizeof (Input)) {
- X itop = erealloc(itop, istacksize *= 2);
- X istack = itop + idiff;
- X }
- X
- X istack->t = t;
- X if (t == FD) {
- X istack->fd = va_arg(ap, int);
- X realgchar = fdgchar;
- X inbuf = ealloc(BUFSIZE + 2);
- X } else {
- X count = strarraylen(a = va_arg(ap, char **));
- X sprint((inbuf = ealloc(count + 3)) + 2, "%a", a);
- X realgchar = stringgchar;
- X }
- X
- X va_end(ap);
- X
- X realugchar = ugalive;
- X chars_out = 2;
- X chars_in = 0;
- X lineno = 1;
- X}
- X
- X/* remove an input source from the stack. restore the right kind of getchar (string,fd) etc. */
- X
- Xvoid popinput() {
- X if (istack->t == FD)
- X close(istack->fd);
- X efree(inbuf);
- X
- X --istack;
- X
- X realgchar = (istack->t == STRING ? stringgchar : fdgchar);
- X
- X if (istack->fd == -1) { /* top of input stack */
- X realgchar = dead;
- X realugchar = ugdead;
- X }
- X
- X inbuf = istack->ibuf;
- X chars_out = istack->index;
- X chars_in = istack->read;
- X lineno = istack->lineno;
- X}
- X
- X/* flush input characters upto newline. Used by scanerror() */
- X
- Xvoid flushu() {
- X int c;
- X
- X if (last == '\n' || last == EOF)
- X return;
- X
- X while ((c = gchar()) != '\n' && c != EOF)
- X ; /* skip to newline */
- X
- X if (c == EOF)
- X ugchar(c);
- X}
- X
- X/* the wrapper loop in rc: prompt for commands until EOF, calling yyparse and walk() */
- X
- XNode *doit(boolean execit) {
- X boolean eof;
- X jmp_buf j;
- X Estack e1, e2;
- X
- X setjmp(j);
- X except(ERROR, j, &e1);
- X
- X for (eof = FALSE; !eof;) {
- X except(ARENA, NULL, &e2);
- X
- X if (dashell) {
- X char *fname[3];
- X
- X fname[1] = concat(varlookup("home"),word("/.rcrc",NULL))->w;
- X fname[2] = NULL;
- X rcrc = TRUE;
- X dashell = FALSE;
- X b_dot(fname);
- X }
- X
- X if (interactive) {
- X Node *f;
- X List *s;
- X
- X if ((f = fnlookup("prompt")) != NULL)
- X walk(treecpy(f, nalloc), TRUE);
- X
- X if ((s = varlookup("prompt")) != NULL) {
- X#ifdef READLINE
- X prompt = s->w;
- X#else
- X fprint(2,"%s",s->w);
- X#endif
- X prompt2 = (s->n == NULL ? "" : s->n->w);
- X }
- X }
- X
- X inityy();
- X
- X if (yyparse() < 0)
- X rc_raise(ERROR);
- X
- X eof = (last == EOF); /* "last" can be clobbered during a walk() */
- X
- X if (execit && parsetree != NULL)
- X walk(parsetree, TRUE);
- X
- X unexcept(); /* ARENA */
- X }
- X
- X popinput();
- X unexcept(); /* ERROR */
- X return parsetree;
- X}
- X
- X/* parse a function imported from the environment */
- X
- XNode *parseline(char *extdef) {
- X char *in[2];
- X int i = interactive;
- X Node *ret;
- X
- X in[0] = extdef;
- X in[1] = NULL;
- X interactive = FALSE;
- X pushinput(STRING, in);
- X ret = doit(FALSE);
- X interactive = i;
- X return ret;
- X}
- X
- X/* write last command out to a file. Check to see if $history has changed, also */
- X
- Xstatic void history() {
- X List *histlist;
- X SIZE_T a;
- X
- X if (!interactive)
- X return;
- X
- X if ((histlist = varlookup("history")) == NULL) {
- X if (histstr != NULL) {
- X efree(histstr);
- X close(histfd);
- X histstr = NULL;
- X }
- X return;
- X }
- X
- X if (histstr == NULL || !streq(histstr, histlist->w)) { /* open new file */
- X if (histstr != NULL) {
- X efree(histstr);
- X close(histfd);
- X }
- X histstr = ecpy(histlist->w);
- X histfd = rc_open(histstr, APPEND);
- X if (histfd < 0) {
- X uerror(histstr);
- X efree(histstr);
- X histstr = NULL;
- X }
- X }
- X
- X /*
- X small unix hack: since read() reads only up to a newline from a terminal, then
- X presumably this write() will write at most only one input line at a time.
- X */
- X
- X for (a = 2; a < chars_in + 2; a++) { /* skip empty lines and comments in history. */
- X if (inbuf[a] == '#' || inbuf[a] == '\n')
- X return;
- X if (inbuf[a] != ' ' && inbuf[a] != '\t')
- X break;
- X }
- X writeall(histfd, inbuf + 2, chars_in);
- X}
- END_OF_FILE
- if test 6937 -ne `wc -c <'input.c'`; then
- echo shar: \"'input.c'\" unpacked with wrong size!
- fi
- # end of 'input.c'
- fi
- if test -f 'lex.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'lex.c'\"
- else
- echo shar: Extracting \"'lex.c'\" \(10083 characters\)
- sed "s/^X//" >'lex.c' <<'END_OF_FILE'
- X/* lex.c: rc's lexical analyzer */
- X
- X#include "rc.h"
- X#include "lex.h"
- X#include "y.tab.h"
- X#include "nalloc.h"
- X#include "input.h"
- X#include "utils.h"
- X#include "hash.h"
- X#include "heredoc.h"
- X
- X/*
- X Special characters (i.e., "non-word") in rc:
- X \t \n # ; & | ^ $ = ~ ` ' { } @ ! ( ) < > \
- X
- X The lexical analyzer is fairly straightforward. The only really unclean part
- X concerns backslash continuation and "double backslashes". A backslash followed by
- X a newline is treated as a space, otherwise backslash is not a special characeter
- X (i.e., it can be part of a word). This introduces a host of unwanted special
- X cases. In our case, \ cannot be a word character, since we wish to read in all
- X word characters in a tight loop.
- X
- X Note: to save the trouble of declaring these arrays with TRUEs and FALSEs, I am assuming
- X that FALSE = 0, TRUE = 1. (and so is it declared in rc.h)
- X*/
- X
- X#define BUFSIZE ((SIZE_T) 1000) /* malloc hates power of 2 buffers? */
- X#define BUFMAX (8 * BUFSIZE) /* How big the buffer can get before we re-allocate the
- X space at BUFSIZE again. Premature optimization? Maybe.
- X */
- X
- Xenum wordstates { NW, RW, KW }; /* "nonword", "realword", "keyword" */
- X
- Xstatic void getpair(int);
- X
- Xint lineno;
- X
- Xconst char nw[] = {
- X 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- X 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- X 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
- X 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- X};
- X
- Xconst char dnw[] = {
- X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
- X 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
- X 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- X 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
- X};
- X
- Xstatic SIZE_T bufsize = BUFSIZE;
- Xstatic char *realbuf = NULL;
- Xstatic boolean newline = FALSE;
- Xstatic enum wordstates word = NW;
- Xstatic int fd_left, fd_right;
- X
- X#define checkfreecaret {if (*wp != NW) { *wp = NW; ugchar(c); return '^'; }}
- X
- Xenum filedescriptors { UNSET = -9, CLOSED = -1 };
- X
- Xint yylex() {
- X static boolean dollar = FALSE;
- X boolean saw_meta = FALSE;
- X int c;
- X SIZE_T i; /* The purpose of all these local assignments is to */
- X const char *meta; /* allow optimizing compilers like gcc to load these */
- X char *buf = realbuf; /* values into registers. On a sparc this is a big */
- X YYSTYPE *y = &yylval; /* win, in code size *and* execution time */
- X enum wordstates *wp = &word;
- X
- X /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
- X meta = (dollar ? dnw : nw);
- X dollar = FALSE;
- X
- X if (newline) {
- X --lineno; /* slight space optimization; print_prompt2() always increments lineno */
- X print_prompt2();
- X newline = FALSE;
- X }
- X
- Xtop: while ((c = gchar()) == ' ' || c == '\t')
- X *wp = NW;
- X
- X if (c == EOF)
- X return END;
- X
- X if (!meta[c]) { /* it's a word or keyword. */
- X checkfreecaret;
- X *wp = RW;
- X i = 0;
- X read: do {
- X buf[i++] = c;
- X if (c == '?' || c == '[' || c == '*')
- X saw_meta = TRUE;
- X if (i >= bufsize)
- X buf = realbuf = erealloc(buf, bufsize *= 2);
- X } while ((c = gchar()) != EOF && !meta[c]);
- X if (c == '\\') {
- X if ((c = gchar()) == '\n') {
- X print_prompt2();
- X c = ' '; /* Pretend a space was read */
- X } else {
- X bs: buf[i++] = '\\';
- X if (!meta[c] || c == '\\')
- X goto read;
- X }
- X }
- X ugchar(c);
- X buf[i] = '\0';
- X *wp = KW;
- X if (i == 2) {
- X if (*buf == 'i' && buf[1] == 'f') return IF;
- X if (*buf == 'f' && buf[1] == 'n') return FN;
- X if (*buf == 'i' && buf[1] == 'n') return IN;
- X }
- X if (streq(buf,"for")) return FOR;
- X if (streq(buf,"else")) return ELSE;
- X if (streq(buf,"switch")) return SWITCH;
- X if (streq(buf,"while")) return WHILE;
- X *wp = RW;
- X y->word.w = ncpy(buf);
- X if (saw_meta) {
- X char *r, *s;
- X
- X y->word.m = nalloc(strlen(buf) + 1);
- X for (r = buf, s = y->word.m; *r != '\0'; r++, s++)
- X *s = (*r == '?' || *r == '[' || *r == '*');
- X } else {
- X y->word.m = NULL;
- X }
- X return WORD;
- X }
- X
- X if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
- X checkfreecaret;
- X if (c == '!' || c == '@' || c == '~')
- X *wp = KW;
- X }
- X
- X switch (c) {
- X case '\0':
- X scanerror("null character");
- X /* NOTREACHED */
- X case '!':
- X return BANG;
- X case '@':
- X return SUBSHELL;
- X case '~':
- X return TWIDDLE;
- X case '`':
- X c = gchar();
- X if (c == '`')
- X return BACKBACK;
- X ugchar(c);
- X return '`';
- X case '$':
- X dollar = TRUE;
- X c = gchar();
- X if (c == '#')
- X return COUNT;
- X if (c == '^')
- X return FLAT;
- X ugchar(c);
- X return '$';
- X case '\'':
- X *wp = RW;
- X i = 0;
- X do {
- X buf[i++] = c;
- X if (c == '\n')
- X print_prompt2();
- X if (c == EOF)
- X scanerror("eof in quoted string");
- X if (i >= bufsize)
- X buf = realbuf = erealloc(buf, bufsize *= 2);
- X } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */
- X ugchar(c);
- X buf[i] = '\0';
- X y->word.w = ncpy(buf);
- X y->word.m = NULL;
- X return WORD;
- X case '\\':
- X if ((c = gchar()) == '\n') {
- X print_prompt2();
- X goto top; /* Pretend it was just another space. */
- X }
- X ugchar(c);
- X c = '\\';
- X checkfreecaret;
- X c = gchar();
- X i = 0;
- X goto bs;
- X case '(':
- X if (*wp == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */
- X c = SUB;
- X *wp = NW;
- X return c;
- X case '#':
- X while ((c = gchar()) != '\n') /* skip comment until newline */
- X if (c == EOF)
- X return END;
- X /* FALLTHROUGH */
- X case '\n':
- X lineno++;
- X newline = TRUE;
- X /* FALLTHROUGH */
- X case ';':
- X case '^':
- X case ')':
- X case '=':
- X case '{': case '}':
- X *wp = NW;
- X return c;
- X case '&':
- X *wp = NW;
- X c = gchar();
- X if (c == '&')
- X return ANDAND;
- X ugchar(c);
- X return '&';
- X case '|':
- X *wp = NW;
- X c = gchar();
- X if (c == '|')
- X return OROR;
- X getpair(c);
- X if ((y->pipe.left = fd_left) == UNSET)
- X y->pipe.left = 1; /* default to fd 1 */
- X if ((y->pipe.right = fd_right) == UNSET)
- X y->pipe.right = 0; /* default to fd 0 */
- X if (y->pipe.right == CLOSED)
- X scanerror("expected digit after '='"); /* can't close a pipe */
- X return PIPE;
- X case '>':
- X c = gchar();
- X if (c == '>') {
- X c = gchar();
- X y->redir.type = APPEND;
- X } else
- X y->redir.type = CREATE;
- X y->redir.fd = 1;
- X goto common;
- X case '<':
- X c = gchar();
- X if (c == '<') {
- X c = gchar();
- X if (c == '<') {
- X c = gchar();
- X y->redir.type = HERESTRING;
- X } else {
- X y->redir.type = HEREDOC;
- X }
- X } else
- X y->redir.type = FROM;
- X y->redir.fd = 0;
- X common:
- X *wp = NW;
- X getpair(c);
- X if (fd_right == UNSET) { /* redirection, not dup */
- X if (fd_left != UNSET)
- X y->redir.fd = fd_left;
- X return REDIR;
- X } else { /* dup; recast yylval */
- X y->dup.type = y->redir.type;
- X y->dup.left = fd_left;
- X y->dup.right = fd_right;
- X return DUP;
- X }
- X default:
- X *wp = NW;
- X return c; /* don't know what it is, let yacc barf on it */
- X }
- X}
- X
- Xvoid skipnl(void) {
- X int c;
- X
- X while ((c = gchar()) == ' ' || c == '\t' || c == '#' || c == '\n') {
- X if (c == '\n' || c == '#') {
- X for (; c != '\n'; c = gchar()) /* skip comments */
- X if (c == EOF) {
- X ugchar(c);
- X return;
- X }
- X print_prompt2();
- X }
- X }
- X ugchar(c);
- X}
- X
- Xvoid yyerror(const char *s) {
- X char *tok;
- X char tokbuf[128];
- X
- X if (!interactive) {
- X if (word != NW)
- X tok = realbuf;
- X else if (last == EOF)
- X tok = "end of input";
- X else if (last == '\n')
- X tok = "end of line";
- X else
- X sprint(tok = tokbuf, (last < 32 || last > 126) ? "(decimal %d)" : "'%c'",last);
- X fprint(2,"line %d: %s near %s\n", lineno - (last == '\n'), s, tok);
- X } else
- X fprint(2,"%s\n",s);
- X}
- X
- Xvoid scanerror(char *s) {
- X flushu(); /* flush upto newline */
- X rc_error(s);
- X}
- X
- Xvoid inityy(void) {
- X newline = FALSE;
- X word = NW;
- X hq = NULL;
- X
- X /* return memory to the system if the buffer got too large */
- X
- X if (bufsize > BUFMAX && realbuf != NULL) {
- X efree(realbuf);
- X bufsize = BUFSIZE;
- X realbuf = ealloc(bufsize);
- X } else if (realbuf == NULL)
- X realbuf = ealloc(bufsize);
- X}
- X
- Xvoid print_prompt2() {
- X lineno++;
- X#ifdef READLINE
- X prompt = prompt2;
- X#else
- X if (interactive)
- X fprint(2,"%s",prompt2);
- X#endif
- X}
- X
- X/*
- X Scan in a pair of integers for redirections like >[2=1]. CLOSED represents a closed file
- X descriptor (i.e., >[2=]) and UNSET represents an undesignated file descriptor (e.g.,
- X >[2] is represented as (2,UNSET).
- X
- X This function makes use of unsigned compares to make range tests in one compare operation.
- X*/
- X
- Xstatic void getpair(int c) {
- X int n;
- X
- X fd_left = fd_right = UNSET;
- X
- X if (c != '[') {
- X ugchar(c);
- X return;
- X }
- X
- X if ((unsigned int) (n = gchar() - '0') > 9)
- X scanerror("expected digit after '['");
- X
- X while ((unsigned int) (c = gchar() - '0') <= 9)
- X n = n * 10 + c;
- X
- X fd_left = n;
- X c += '0';
- X
- X switch (c) {
- X default:
- X scanerror("expected '=' or ']' after digit");
- X /* NOTREACHED */
- X case ']':
- X return;
- X case '=':
- X if ((unsigned int) (n = gchar() - '0') > 9) {
- X if (n != ']' - '0')
- X scanerror("expected digit or ']' after '='");
- X fd_right = CLOSED;
- X } else {
- X while ((unsigned int) (c = gchar() - '0') <= 9)
- X n = n * 10 + c;
- X if (c != ']' - '0')
- X scanerror("expected ']' after digit");
- X fd_right = n;
- X }
- X }
- X}
- END_OF_FILE
- if test 10083 -ne `wc -c <'lex.c'`; then
- echo shar: \"'lex.c'\" unpacked with wrong size!
- fi
- # end of 'lex.c'
- fi
- if test -f 'walk.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'walk.c'\"
- else
- echo shar: Extracting \"'walk.c'\" \(8357 characters\)
- sed "s/^X//" >'walk.c' <<'END_OF_FILE'
- X/* walk.c: walks the parse tree. */
- X
- X#include <setjmp.h>
- X#include <signal.h>
- X#include "rc.h"
- X#include "utils.h"
- X#include "status.h"
- X#include "exec.h"
- X#include "walk.h"
- X#include "glom.h"
- X#include "hash.h"
- X#include "glob.h"
- X#include "lex.h"
- X#include "open.h"
- X#include "except.h"
- X
- Xboolean cond = FALSE;
- X
- Xstatic boolean iscase(Node *);
- Xstatic boolean isallpre(Node *);
- Xstatic boolean dofork(void);
- X
- X/* walk the parse-tree. "obvious". */
- X
- Xboolean walk(Node *n, boolean parent) {
- X if (n == NULL) {
- X if (!parent)
- X exit(0);
- X set(TRUE);
- X return TRUE;
- X }
- X
- X switch (n->type) {
- X case ARGS: case BACKQ: case CONCAT: case rCOUNT: case rFLAT:
- X case LAPPEND: case rREDIR: case VAR: case VARSUB: case rWORD:
- X exec(glob(glom(n)), parent); /* simple command */
- X break;
- X case BODY:
- X walk(n->u[0].p, TRUE);
- X walk(n->u[1].p, TRUE);
- X break;
- X case NOWAIT: {
- X int pid;
- X char apid[8];
- X
- X switch (pid = fork()) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X setsigdefaults();
- X#ifdef NOJOB
- X signal(SIGINT, SIG_IGN); /* traditional backgrounding procedure: ignore SIGINT */
- X#else
- X signal(SIGTTOU, SIG_IGN); /* Berkeleyized version: put it in a new pgroup. */
- X signal(SIGTTIN, SIG_IGN);
- X signal(SIGTSTP, SIG_IGN);
- X setpgrp(0, getpid());
- X#endif
- X dup2(rc_open("/dev/null", FROM), 0);
- X walk(n->u[0].p, FALSE);
- X exit(getstatus());
- X /* NOTREACHED */
- X default:
- X if (interactive)
- X fprint(2,"%d\n",pid);
- X varassign("apid", word(sprint(apid,"%d",pid), NULL), FALSE);
- X redirq = NULL; /* kill pre-redir queue */
- X fifoq = NULL;
- X }
- X break;
- X }
- X case rANDAND: {
- X boolean oldcond = cond;
- X
- X cond = TRUE;
- X if (walk(n->u[0].p, TRUE)) {
- X cond = oldcond;
- X walk(n->u[1].p, TRUE);
- X } else
- X cond = oldcond;
- X break;
- X }
- X case rOROR: {
- X boolean oldcond = cond;
- X
- X cond = TRUE;
- X if (!walk(n->u[0].p, TRUE)) {
- X cond = oldcond;
- X walk(n->u[1].p, TRUE);
- X } else
- X cond = oldcond;
- X break;
- X }
- X case rBANG:
- X set(!walk(n->u[0].p, TRUE));
- X break;
- X case rIF: {
- X boolean oldcond = cond;
- X Node *true_cmd = n->u[1].p, *false_cmd = NULL;
- X
- X if (true_cmd != NULL && true_cmd->type == rELSE) {
- X false_cmd = true_cmd->u[1].p;
- X true_cmd = true_cmd->u[0].p;
- X }
- X cond = TRUE;
- X if (!walk(n->u[0].p, TRUE))
- X true_cmd = false_cmd; /* run the else clause */
- X cond = oldcond;
- X walk(true_cmd, TRUE);
- X break;
- X }
- X case rWHILE: {
- X jmp_buf j;
- X boolean oldcond = cond;
- X Estack e1,e2;
- X
- X cond = TRUE;
- X
- X if (!walk(n->u[0].p, TRUE)) { /* prevent spurious breaks inside test */
- X cond = oldcond;
- X break;
- X }
- X
- X if (setjmp(j))
- X break;
- X
- X except(BREAK, j, &e1);
- X do {
- X cond = oldcond;
- X except(ARENA, NULL, &e2);
- X walk(n->u[1].p, TRUE);
- X unexcept(); /* ARENA */
- X cond = TRUE;
- X } while (walk(n->u[0].p, TRUE));
- X cond = oldcond;
- X unexcept(); /* BREAK */
- X break;
- X }
- X case FORIN: {
- X List *l;
- X jmp_buf j;
- X Estack e1,e2;
- X
- X if (setjmp(j))
- X break;
- X
- X except(BREAK, j, &e1);
- X for (l = glob(glom(n->u[1].p)); l != NULL; l = l->n) {
- X assign(glom(n->u[0].p), word(l->w, NULL), FALSE);
- X except(ARENA, NULL, &e2);
- X walk(n->u[2].p, TRUE);
- X unexcept(); /* ARENA */
- X }
- X unexcept(); /* BREAK */
- X break;
- X }
- X case rSUBSHELL:
- X if (dofork()) {
- X setsigdefaults();
- X walk(n->u[0].p, TRUE);
- X rc_exit(getstatus());
- X }
- X break;
- X case ASSIGN:
- X if (n->u[0].p == NULL)
- X rc_error("null variable name");
- X assign(glom(n->u[0].p), glob(glom(n->u[1].p)), FALSE);
- X set(TRUE);
- X break;
- X case rPIPE: {
- X int i, j, k, sp, pid, wpid, fd_prev, fd_out, pids[512], stats[512], p[2];
- X void (*handler)(int);
- X Node *r;
- X
- X fd_prev = fd_out = 1;
- X
- X for (r = n, i = 0; r != NULL && r->type == rPIPE; r = r->u[2].p, i++) {
- X if (i > 500) /* the only hard-wired limit in rc? */
- X rc_error("pipe too long");
- X
- X if (pipe(p) < 0) {
- X uerror("pipe");
- X rc_error(NULL);
- X }
- X
- X switch (pid = fork()) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X setsigdefaults();
- X redirq = NULL; /* clear preredir queue */
- X fifoq = NULL;
- X dup2(p[0],r->u[1].i);
- X if (fd_prev != 1) {
- X dup2(fd_prev, fd_out);
- X close(fd_prev);
- X }
- X close(p[0]);
- X close(p[1]);
- X walk(r->u[3].p, FALSE);
- X exit(getstatus());
- X /* NOTREACHED */
- X default:
- X if (fd_prev != 1)
- X close(fd_prev); /* parent must close all pipe fd's */
- X pids[i] = pid;
- X fd_prev = p[1];
- X fd_out = r->u[0].i;
- X close(p[0]);
- X }
- X }
- X
- X switch (pid = fork()) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X setsigdefaults();
- X dup2(fd_prev, fd_out);
- X close(fd_prev);
- X walk(r, FALSE);
- X exit(getstatus());
- X /* NOTREACHED */
- X default:
- X redirq = NULL; /* clear preredir queue */
- X fifoq = NULL;
- X close(fd_prev);
- X pids[i++] = pid;
- X
- X /* collect statuses */
- X
- X if ((handler = signal(SIGINT, SIG_IGN)) == SIG_DFL)
- X signal(SIGINT, SIG_DFL); /* don't ignore interrupts in noninteractive mode */
- X
- X for (k = i; k != 0;) {
- X if ((wpid = wait(&sp)) < 0)
- X uerror("wait");
- X for (j = 0; j < i; j++)
- X if (wpid == pids[j]) {
- X stats[j] = sp;
- X pids[j] = 0;
- X --k;
- X }
- X }
- X
- X setpipestatus(stats, i);
- X signal(SIGINT, handler);
- X }
- X break;
- X }
- X case NEWFN: {
- X List *l = glom(n->u[0].p);
- X
- X if (l == NULL)
- X rc_error("null function name");
- X while (l != NULL) {
- X fnassign(l->w, n->u[1].p);
- X l = l->n;
- X }
- X set(TRUE);
- X break;
- X }
- X case RMFN: {
- X List *l = glom(n->u[0].p);
- X
- X while (l != NULL) {
- X fnrm(l->w);
- X l = l->n;
- X }
- X set(TRUE);
- X break;
- X }
- X case rDUP:
- X break; /* Null command */
- X case MATCH:
- X set(lmatch(glob(glom(n->u[0].p)), glom(n->u[1].p)));
- X break;
- X case rSWITCH: {
- X List *v = glom(n->u[0].p);
- X
- X while (1) {
- X do {
- X n = n->u[1].p;
- X if (n == NULL || n->type != BODY)
- X return istrue();
- X } while (!iscase(n->u[0].p));
- X if (lmatch(v, glom(n->u[0].p)->n)) {
- X for (n = n->u[1].p; n != NULL && !iscase(n->u[0].p); n = n->u[1].p) {
- X if (n->type != BODY) { /* special case at the end of BODY subtree */
- X walk(n, TRUE);
- X break;
- X }
- X walk(n->u[0].p, TRUE);
- X }
- X break;
- X }
- X }
- X break;
- X }
- X case PRE: {
- X List *v;
- X
- X if (n->u[0].p->type == rREDIR) {
- X qredir(n->u[0].p);
- X walk(n->u[1].p, TRUE);
- X break;
- X } else if (n->u[0].p->type == ASSIGN) {
- X if (isallpre(n->u[1].p)) {
- X walk(n->u[0].p, TRUE);
- X walk(n->u[1].p, TRUE);
- X break;
- X } else {
- X v = glom(n->u[0].p->u[0].p);
- X assign(v, glob(glom(n->u[0].p->u[1].p)), TRUE);
- X walk(n->u[1].p, TRUE);
- X varrm(v->w, TRUE);
- X }
- X } else
- X rc_error("walk: node other than assign or redir in PRE. help!");
- X break;
- X }
- X case BRACE:
- X if (dofork()) {
- X setsigdefaults();
- X walk(n->u[1].p, TRUE); /* Do redirections */
- X redirq = NULL; /* Reset redirection queue */
- X walk(n->u[0].p, TRUE); /* Do commands */
- X rc_exit(getstatus());
- X /* NOTREACHED */
- X }
- X break;
- X case EPILOG:
- X qredir(n->u[0].p);
- X if (n->u[1].p != NULL)
- X walk(n->u[1].p, TRUE); /* Do more redirections. */
- X else
- X doredirs(); /* Okay, we hit the bottom. */
- X break;
- X case NMPIPE:
- X rc_error("named pipes cannot be executed as commands");
- X /* NOTREACHED */
- X default:
- X rc_error("walk: unknown node; this can't happen");
- X /* NOTREACHED */
- X }
- X return istrue();
- X}
- X
- X/* checks a "command-line" (in parsetree form) to see if it contains the fake keyword "case". */
- X
- Xstatic boolean iscase(Node *n) {
- X if (n == NULL)
- X return FALSE;
- X
- X switch (n->type) {
- X case rWORD:
- X return streq(n->u[0].s, "case");
- X case ARGS: case LAPPEND:
- X return iscase(n->u[0].p);
- X default:
- X return FALSE;
- X }
- X}
- X
- X/* checks to see whether a subtree is all pre-command directives, i.e., assignments and redirs only */
- X
- Xstatic boolean isallpre(Node *n) {
- X if (n == NULL)
- X return TRUE;
- X
- X switch (n->type) {
- X case PRE:
- X return isallpre(n->u[1].p);
- X case rREDIR: case ASSIGN: case rDUP:
- X return TRUE;
- X default:
- X return FALSE;
- X }
- X}
- X
- X/*
- X A code-saver. Forks, child returns (for further processing in walk()), and the parent
- X waits for the child to finish, setting $status appropriately.
- X*/
- X
- Xstatic boolean dofork() {
- X int pid, sp;
- X
- X switch (pid = fork()) {
- X case -1:
- X uerror("fork");
- X rc_error(NULL);
- X /* NOTREACHED */
- X case 0:
- X return TRUE;
- X default:
- X redirq = NULL; /* clear out the pre-redirection queue in the parent */
- X fifoq = NULL;
- X while (pid != wait(&sp))
- X if (pid < 0)
- X uerror("wait");
- X setstatus(sp);
- X return FALSE;
- X }
- X}
- X
- END_OF_FILE
- if test 8357 -ne `wc -c <'walk.c'`; then
- echo shar: \"'walk.c'\" unpacked with wrong size!
- fi
- # end of 'walk.c'
- fi
- echo shar: End of archive 2 \(of 4\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-